package com.evendai.sipdemo.util

import android.os.Environment
import android.preference.PreferenceManager
import org.doubango.ngn.utils.Aes
import org.doubango.ngn.utils.NgnConfigurationEntry
import com.evendai.loglibrary.Timber
import com.evendai.sipdemo.App
import com.evendai.sipdemo.Keys
import org.doubango.ngn.NgnEngine
import org.doubango.utils.Util
import java.io.File
import java.io.FileReader
import java.io.FileWriter
import java.util.*

/**
 * 存储工具，用于把数据持久化到SharedPreferences中
 */
object StorageUtil {

    private val pref = PreferenceManager.getDefaultSharedPreferences(App.getContext())
    private val editor = pref.edit()
    private val TAG = StorageUtil::class.java.simpleName
    private const val KEY_ACTION_RECORD_COUNT = "actionRecordCount"

    @Suppress("unused")
    fun putInt(key: String, value: Int) = editor.putInt(encrypt(key), value).apply()
    fun getInt(key: String)= pref.getInt(encrypt(key), 0)
    fun getInt(key: String, defValue: Int)= pref.getInt(encrypt(key), defValue)
    fun putLong(key: String, value: Long) = editor.putLong(encrypt(key), value).apply()
    fun getLong(key: String) = pref.getLong(encrypt(key), 0)
    fun putBoolean(key: String, value: Boolean) = editor.putBoolean(encrypt(key), value).apply()
    fun getBoolean(key: String) = pref.getBoolean(encrypt(key), false)
    fun getBoolean(key: String, defValue: Boolean) = pref.getBoolean(encrypt(key), defValue)
    fun putString(key: String, value: String) = editor.putString(encrypt(key), encrypt(value)).apply()
    fun getStringOrNull(key: String): String? {
        val string = pref.getString(encrypt(key), null)
        return string?.let { decrypt(it) }
    }
    @Suppress("MemberVisibilityCanBePrivate")
    fun getLong(key: String, defValue: Long): Long {
        return pref.getLong(encrypt(key), defValue)
    }

    fun getString(key: String, defValue: String): String {
        var string = pref.getString(encrypt(key), defValue)
        if (string != null && string != defValue) {
            string = decrypt(string)
        }
        return string!!
    }

    fun saveActionRecordCount(value: Long) = putStringToSDCard(KEY_ACTION_RECORD_COUNT, value.toString(), false)

    fun getActionRecordCount() = getLongBySdcard(KEY_ACTION_RECORD_COUNT, false)

    fun putBallId(ballId: String) {
        putStringToSpAndSdcard(Keys.BALL_ID, ballId)
    }

    fun getBallId(): String? {
        var ballId = getStringOrNull(Keys.BALL_ID)
        if (ballId.isNullOrBlank()) {
            ballId = getStringBySDCard(Keys.BALL_ID)
            if (Utils.isValidBallId(ballId)) {
                putString(Keys.BALL_ID, ballId!!)
            }
        }
        return ballId
    }

    fun putSipServerIp(sipServerIp: String) {
        NgnEngine.getInstance().configurationService.putString(NgnConfigurationEntry.NETWORK_PCSCF_HOST, sipServerIp, true)
        putStringToSpAndSdcard(Keys.SIP_SERVER_IP, sipServerIp)
    }

    fun getSipServerIp(): String {
        var sipServerIp: String? = NgnEngine.getInstance().configurationService.getString(NgnConfigurationEntry.NETWORK_PCSCF_HOST, null)
        if (sipServerIp.isNullOrBlank()) {
            sipServerIp = getStringOrNull(Keys.SIP_SERVER_IP)
            if (sipServerIp.isNullOrBlank()) {
                sipServerIp = getStringBySDCard(Keys.SIP_SERVER_IP)
                if (!sipServerIp.isNullOrBlank() && Util.isIpAddress(sipServerIp)) {
                    NgnEngine.getInstance().configurationService.putString(NgnConfigurationEntry.NETWORK_PCSCF_HOST, sipServerIp, true)
                    putString(Keys.SIP_SERVER_IP, sipServerIp)
                }
            }
        }
        return sipServerIp ?: ""
    }

    /** 保存String到SharedPreferences和SDCard中 */
    @Suppress("unused")
    fun putStringToSpAndSdcard(key: String, content: String) {
        putString(key, content)
        putStringToSDCard(key, content)
    }

    @Suppress("MemberVisibilityCanBePrivate")
    fun getLongBySdcard(key: String, encrypt: Boolean): Long {
        var long = 0L
        val longString = getStringBySDCard(key, encrypt)
        if (longString != null) {
            try {
                long = longString.toLong()
            } catch (e: Exception) {
                Timber.e("把SDCard中读到的String转换为long出现异常, string = $longString")
            }

        }
        return long
    }

    @Suppress("unused")
    fun putLongToSpAndSdcard(key: String, long: Long) {
        putLong(key, long)
        putStringToSDCard(key, long.toString())
    }

    @Suppress("unused")
    fun getLongFromSpAndSdcard(key: String): Long {
        val defaultValue = -987654321L
        var value = getLong(key, defaultValue)
        if (value == defaultValue) {
            value = getLongBySdcard(key, true)
        }
        return value
    }

    @Suppress("unused")
    fun getStringFromSpAndSdcard(key: String): String? {
        var value = getStringOrNull(key)
        if (value.isNullOrBlank()) {
            value = getStringBySDCard(key)
        }
        return value
    }

    @Suppress("MemberVisibilityCanBePrivate")
    fun getStringBySDCard(key: String): String? {
        val configFile = createConfigFile()
        configFile?.let { file ->
            try {
                return FileReader(file).use { reader ->
                    val properties = Properties()
                    properties.load(reader)
                    var value = properties.getProperty(encrypt(key))
                    value = value?.let { decrypt(it) }
                    Timber.e("从SDCard中读取的属性：$key = $value", Exception())
                    value
                }
            } catch (ex: Exception) {
                Timber.e("从SDCard中的配置文件中读取'$key'属性时出现异常", ex)
            }
        }
        return null
    }

    @Suppress("MemberVisibilityCanBePrivate")
    fun getStringBySDCard(key: String, encrypt: Boolean): String? {
        val configFile = createConfigFile()
        configFile?.let { file ->
            try {
                return FileReader(file).use { reader ->
                    val properties = Properties()
                    properties.load(reader)
                    var value = properties.getProperty(if (encrypt) encrypt(key) else key)
                    value = value?.let { if (encrypt) decrypt(it) else it }
                    Timber.e("从SDCard中读取的属性：$key = $value")
                    value
                }
            } catch (ex: Exception) {
                Timber.e("从SDCard中的配置文件中读取'$key'属性时出现异常", ex)
            }
        }
        return null
    }

    /** 保存到DaZhou/BallConfigs.txt文件中 */
    @Suppress("MemberVisibilityCanBePrivate")
    fun putStringToSDCard(key: String, value: String) {
        putStringToSDCard(key, value, true)
    }

    fun putStringToSDCard(key: String, value: String, isEncrypt: Boolean) {
        val configFile = createConfigFile()
        configFile?.let { file ->
            try {
                FileReader(file).use { reader ->
                    val properties = Properties()
                    properties.load(reader)
                    FileWriter(file).use { writer ->
                        properties.setProperty(if (isEncrypt) encrypt(key) else key, if (isEncrypt) encrypt(value) else value)
                        properties.store(writer, null)
                    }
                }
            } catch (ex: Exception) {
                Timber.e("保存 $key = $value 到SD卡配置文件中时出现异常", ex)
            }
        }
    }

    private fun encrypt(str: String) = Aes.encrypt(str)
    private fun decrypt(str: String) = Aes.decrypt(str)

    private fun createConfigFile(): File? {
        if (Environment.MEDIA_MOUNTED == Environment.getExternalStorageState()) {
            try {
                val configFileSaveDir = File(Environment.getExternalStorageDirectory(), "Monitor")
                var hasDir = configFileSaveDir.exists()
                if (!hasDir) hasDir = configFileSaveDir.mkdirs()
                if (hasDir) {
                    val configFile = File(configFileSaveDir, "MonitorConfigs.txt")
                    if (!configFile.exists()) configFile.createNewFile()
                    return configFile
                } else {
                    Timber.e("创建配置文件目录失败", Exception())
                }
            } catch (e: Exception) {
                Timber.e("创建配置文件时出现异常", Exception())
            }
        } else {
            Timber.e("SDCard不可用", Exception("SDCard不可用"))
        }
        return null
    }

    fun saveLine(fileName: String, line: String) {
        if (Environment.MEDIA_MOUNTED == Environment.getExternalStorageState()) {
            try {
                val configFileSaveDir = File(Environment.getExternalStorageDirectory(), "Monitor")
                var hasDir = configFileSaveDir.exists()
                if (!hasDir) hasDir = configFileSaveDir.mkdirs()
                if (hasDir) {
                    val configFile = File(configFileSaveDir, fileName)
                    if (!configFile.exists()) configFile.createNewFile()
                    val writer = FileWriter(configFile, true)
                    writer.write("${line}\n")
                    writer.close()
                } else {
                    Timber.e("创建配置文件目录失败", Exception())
                }
            } catch (e: Exception) {
                Timber.e("创建配置文件时出现异常", Exception())
            }
        }
    }

}